use std::{
    fmt::Display,
    ops::{Add, Sub},
    str::FromStr,
};

#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)]
pub struct Year(usize);

impl Add<Month> for Year {
    type Output = f32;

    fn add(self, rhs: Month) -> Self::Output {
        let y: usize = self.into();
        let m: usize = rhs.into();
        (y + m / 12) as f32 + (m % 12) as f32 / 12.0
    }
}

impl Display for Year {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}

impl Sub for Year {
    type Output = Self;

    fn sub(self, rhs: Self) -> Self::Output {
        Year(self.0 - rhs.0)
    }
}

impl Add for Year {
    type Output = Self;

    fn add(self, rhs: Self) -> Self::Output {
        Year(self.0 + rhs.0)
    }
}

impl Into<usize> for Year {
    fn into(self) -> usize {
        self.0
    }
}

impl From<usize> for Year {
    fn from(value: usize) -> Self {
        Self(value)
    }
}

impl FromStr for Year {
    type Err = std::num::ParseIntError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let _t = s.parse::<usize>()?;
        Ok(Year(_t))
    }
}

#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)]
pub struct Month(usize);

impl Display for Month {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{:02}", self.0)
    }
}

impl From<usize> for Month {
    fn from(value: usize) -> Self {
        Self(value)
    }
}

impl Into<usize> for Month {
    fn into(self) -> usize {
        self.0
    }
}

impl FromStr for Month {
    type Err = std::num::ParseIntError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let _t = s.parse::<usize>()?;
        Ok(Month(_t))
    }
}

#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Clone, Copy)]
pub struct Date(Year, Month);

impl Sub for Date {
    type Output = i32;

    fn sub(self, rhs: Self) -> Self::Output {
        let y: usize = self.0.into();
        let y_r: usize = rhs.0.into();
        let m: usize = self.1.into();
        let m_r: usize = rhs.1.into();
        let res;
        if self > rhs {
            let mut _t = 0;
            let diff_y = y - y_r;
            _t += diff_y * 12;
            let diff_m = m - m_r;
            _t += diff_m;
            res = _t as i32;
        } else {
            let mut _t = 0;
            let diff_y = y_r - y;
            _t += diff_y * 12;
            let diff_m = m_r - m;
            _t += diff_m;
            res = -(_t as i32);
        }
        res
    }
}

impl Display for Date {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}-{}", self.0, self.1)
    }
}

impl Sub<Year> for Date {
    type Output = Self;

    fn sub(self, rhs: Year) -> Self::Output {
        Self(self.0 - rhs, self.1)
    }
}

impl Add<Year> for Date {
    type Output = Date;

    fn add(self, rhs: Year) -> Self::Output {
        Date(self.0 + rhs, self.1)
    }
}

impl Add<Month> for Date {
    type Output = Date;

    fn add(self, rhs: Month) -> Self::Output {
        let m_o: usize = self.1.into();
        let m_r: usize = rhs.into();
        let y = Into::<usize>::into(self.0) + (m_o - 1 + m_r) / 12;
        let m = (m_o - 1 + m_r) % 12 + 1;
        Self(Year(y), Month(m))
    }
}

impl FromStr for Date {
    type Err = std::num::ParseIntError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let mut _t = s.split('-');
        let year: usize = _t.next().unwrap().parse()?;
        let month: usize = _t.next().unwrap().parse::<usize>()?;
        Ok(Self(Year(year), Month(month)))
    }
}

const BASE_RETIRE_DATE: Date = Date(Year(2025), Month(1));
const MALE_RETIRE_YEAR: Year = Year(60);
const MALE_DELAY_MONTH: Month = Month(4);
const MALE_MAX_DELAY_MONTH: Month = Month(36);

const FEMALE_RETIRE_YEAR_50: Year = Year(50);
const FEMALE_DELAY_MONTH_50: Month = Month(2);
const FEMALE_MAX_DELAY_MONTH_50: Month = Month(60);

const FEMALE_RETIRE_YEAR_55: Year = Year(55);
const FEMALE_DELAY_MONTH_55: Month = Month(4);
const FEMALE_MAX_DELAY_MONTH_55: Month = Month(36);

pub fn basic_retire(
    birth: Date,
    retire_year: Year,
    delay_base_month: Month,
    max_delay_month: Month,
) -> String {
    let base_birth_male: Date = BASE_RETIRE_DATE - retire_year;
    let max_delay_month = Into::<usize>::into(max_delay_month) as i32;
    if birth < base_birth_male {
        let retire_date = birth + retire_year;
        return format!("{retire_date},{retire_year},0");
    }
    let mut retire_delay_month =
        (birth - base_birth_male) / Into::<usize>::into(delay_base_month) as i32 + 1;
    if retire_delay_month > max_delay_month {
        retire_delay_month = max_delay_month;
    }
    let retire_date = birth + retire_year + Month(retire_delay_month as usize);
    if retire_delay_month % 12 == 0 {
        return format!(
            "{},{:.2},{}",
            retire_date,
            Into::<usize>::into(retire_year) + (retire_delay_month / 12) as usize,
            retire_delay_month
        );
    } else {
        let retire_year = retire_year + Month(retire_delay_month as usize);
        return format!("{},{:.2},{}", retire_date, retire_year, retire_delay_month);
    }
}

pub fn retire_time(time: &str, tp: &str) -> String {
    let birth = time.parse::<Date>().unwrap();
    if tp == "男职工" {
        basic_retire(
            birth,
            MALE_RETIRE_YEAR,
            MALE_DELAY_MONTH,
            MALE_MAX_DELAY_MONTH,
        )
    } else if tp == "原法定退休年龄55周岁女职工" {
        basic_retire(
            birth,
            FEMALE_RETIRE_YEAR_55,
            FEMALE_DELAY_MONTH_55,
            FEMALE_MAX_DELAY_MONTH_55,
        )
    } else if tp == "原法定退休年龄50周岁女职工" {
        basic_retire(
            birth,
            FEMALE_RETIRE_YEAR_50,
            FEMALE_DELAY_MONTH_50,
            FEMALE_MAX_DELAY_MONTH_50,
        )
    } else {
        unreachable!()
    }
}
